<?php

namespace system\core;

Abstract class abstractAttributemanager
{

	private $collection;
	private $lastHasResult;

	function addAttribute($attributeObject)
	{
		$lowercasekey = $attributeObject->lowercase()->getKey();
		if( $this->hasAttribute($lowercasekey) )
		{
			$this->getAttribute($lowercasekey)->setValue($attributeObject->getValue());
		}
		else
		{
			$this->addToCollection($attributeObject);
		}
	}

	private function addToCollection($object)
	{
		$this->collection[$object->getKey()] = $object;
	}

	function getAttribute($key)
	{
		//Shortcut for precise people...
		if( isset($this->collection[strtolower($key)]) ) return $this->collection[strtolower($key)];

		if( strtolower($this->getLastHasResult()) == strtolower($key) && $this->collection[$this->getLastHasResult()] )
		{
			return $this->collection[$this->getLastHasResult()];
		}

		if( $this->collection ) foreach( $this->collection as $storedKey => $attribute )
			{
				if( strtolower($storedKey) == $key )
				{
					return $attribute;
				}
			}
		return false;
	}

	function getAttributes()
	{
		return $this->collection;
	}

	function hasAttribute($key)
	{
		//Shortcut for precise people...
		if( isset($this->collection[strtolower($key)]) ) return true;

		if( $this->collection ) foreach( $this->collection as $storedKey => $attribute )
			{
				if( strtolower($storedKey) == $key )
				{
					$this->setLastHasResult($storedKey);
					return true;
				}
			}
		return false;
	}

	public function removeAttribute($key)
	{
		unset($this->collection[strtolower($key)]);
	}

	private function setLastHasResult($key)
	{
		$this->lastHasResult = $key;
	}

	private function getLastHasResult()
	{
		return $this->lastHasResult;
	}

	function findAttributeKey($needle, $operator="=")
	{
		if( $this->collection ) foreach( $this->collection as $attribute )
			{
				if( $this->evalStringByOperator($attribute->getKey(), $operator, $needle) )
				{
					return $attribute;
				}
			}
		return false;
	}

	function findAttributeValue($needle, $operator="=")
	{
		if( $this->collection ) foreach( $this->collection as $attribute )
			{
				if( $this->evalStringByOperator($attribute->getValue(), $operator, $needle) )
				{
					return $attribute;
				}
			}
		return false;
	}

	private function evalStringByOperator($haystack, $operator, $needle)
	{
		$hs = "Haystack[{$haystack}]";
		$nl = "Needle[{$needle}]";
		$searchOperatorIndex["="] = "{$nl} Matches Exactly {$hs}"; //Needle is exactly equal to haystack
		$searchOperatorIndex["|="] = "{$hs} Contains Prefix {$nl}"; //Needle is prefix of haystack
		$searchOperatorIndex["*="] = "{$hs} Contains Selector {$nl}"; //Needle is somewhere in the haystack
		$searchOperatorIndex["~="] = "{$hs} Contains Word Selector {$nl}"; //Needle is a full word somewhere in the haystack
		$searchOperatorIndex["$="] = "{$hs} Ends With Selector {$nl}"; //Needle matches the end of the haystack
		$searchOperatorIndex["!="] = "{$nl} Not Equal To {$hs}"; //Needle is not equal to haystack
		$searchOperatorIndex["^="] = "{$hs} Starts With Selector {$nl}"; //Needle matches the beginning of the haystack

		$translateOperator["="] = "Matches Exactly";
		$translateOperator["|="] = "Contains Prefix";
		$translateOperator["*="] = "Contains Selector";
		$translateOperator["~="] = "Contains Word Selector";
		$translateOperator["$="] = "Ends With Selector";
		$translateOperator["!="] = "Not Equal To";
		$translateOperator["^="] = "Starts With Selector";

		if( !isset($searchOperatorIndex[$operator]) ) throw new Exception("Unknown compare operator [{$operator}]");
//		echo "Debug: ".$searchOperatorIndex[$operator]."\n";

		$haystackLen = strlen($haystack);
		$needleLen = strlen($needle);
		if( $needle ) $matchAtPos = strpos($haystack, $needle);

		switch ($operator)
		{
			case "=":
				return ($haystack == $needle ? true : false);
				break;
			case "!=":
				return ($haystack != $needle ? true : false);
				break;
			case "*=":
				return ($matchAtPos !== false ? true : false);
				break;
			case "|=":
				$condition1 = ($matchAtPos === 0);
				$condition2 = (substr($haystack, $needleLen, 1) === "-");
				return (($condition1 && $condition2) === true);
				break;
			case "~=":
				$condition1 = ($needleLen > 0);
				$pieces = explode(" ", $haystack);
				$condition2 = in_array($needle, $pieces);
				return (($condition1 && $condition2) === true);
				break;
			case "^=":
				$condition1 = ($matchAtPos === 0);
				return ($condition1 === true ? true : false);
				break;
			case "$=":
				$condition1 = (($matchAtPos + $needleLen) == $haystackLen);
				return ($condition1 === true ? true : false);
				break;
			default:
				return false;
		}
	}

	public function has($expr)
	{
		$expr = trim($expr);
		$lastsign = substr($expr, -1, 1);
		if( $lastsign == "'" || $lastsign == '"' ) $delimiter = $lastsign;
		preg_match("/\|=|\*=|\~=|\$=|\!=|\^=|=/", $expr, $splitsign);
		$operator = $splitsign = $splitsign[0];
		if( !$splitsign )
		{
			$key = $expr;
			$val = false;
		}
		else
		{
			list($key, $val) = explode($splitsign, $expr);
		}
		if( $delimiter )
		{
			if( $val[0] == $delimiter )
			{
				$val = substr($val, 1, -1);
			}
		}

//		echo "$key, $val, $delimiter, $operator\n";
		$thisHasKey = $this->hasAttribute($key);
		if( !$val && $thisHasKey ) return true;
		elseif( !$thisHasKey ) return false;

		$attrKey = $this->getAttribute($key)->getKey();
		$attrVal = $this->getAttribute($key)->getValue();
		return $this->evalStringByOperator($attrVal, $operator, $val);
	}

}

?>
